from .base_strategy import BaseStrategy
import backtrader as bt
import backtrader.indicators as btind
import indicator.MyTTIndicator as Mytt
import indicator.myzhibiao as mmm


###
# 1均线趋势策略
# 上穿均线关注信号，后一根k先确认信号则开单，如果后一根k线是阳线则触发开单信号，如果是阴线，则再观察一根k线，
# 如果是阳线，并且收盘价仍然在均线上方，则也可以触发开单信号
# 止损在关注信号的最低点
# 当盈亏比达到1：2时，平仓一半，当收盘价跌破均线时，平仓
# 通过仓位管理控制每单最大亏损为1%
# 
# #
class MyStrategy(BaseStrategy):
    params = (
        ('ema_period', 100),      # EMA周期
        ('risk_per_trade', 0.01), # 每笔交易最大风险1%
        ('printlog', False),      # 是否打印日志
    )

 
    def __init__(self):
        super().__init__()

        # 初始化EMA指标
        self.ema = btind.ExponentialMovingAverage(
            self.data.close, period=self.p.ema_period)
        
        # 跟踪变量
        self.order = None         # 跟踪订单
        self.my_entry_price = 0.0    # 入场价格
        self.entry_low = 0.0      # 入场K线的最低价(用于止损)
        self.stop_price = 0.0     # 止损价格
        self.target_price = 0.0   # 目标价格(用于部分平仓)
        self.half_closed = False  # 是否已经平仓一半
        
        # 用于跟踪信号
        self.crossover = btind.CrossOver(self.data.close, self.ema)
        self.signal_bar = None    # 记录信号出现的bar


    def start(self):
        pass

    def notify_order(self, order):
        super().notify_order(order)
        if order.status in [order.Submitted, order.Accepted]:
            return
 
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log(f'买入执行, 价格: {order.executed.price:.2f}, 数量: {order.executed.size}, 成本: {order.executed.value:.2f}')
                self.my_entry_price = order.executed.price
            elif order.issell():
                self.log(f'卖出执行, 价格: {order.executed.price:.2f}, 数量: {order.executed.size}, 成本: {order.executed.value:.2f}')
 
            self.bar_executed = len(self)
 
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('订单取消/保证金不足/拒绝')
 
        self.order = None

    def notify_trade(self, trade):
        super().notify_trade(trade)

    def calculate_position_size(self):
        """计算固定风险比例的仓位大小"""
        account_value = self.broker.getvalue()
        risk_amount = account_value * self.p.risk_per_trade
        
        if hasattr(self, 'stop_price') and self.stop_price > 0:
            price = self.data.close[0]
            stop_distance = abs(price - self.stop_price) / price  # 止损距离(百分比)
            
            if stop_distance > 0:
                # 计算应该交易的金额: 风险金额 / 止损百分比
                trade_value = risk_amount / stop_distance
                # 转换为具体数量 (四舍五入到整数)
                size = int(trade_value / price)
                return max(size, 1)  # 至少交易1单位
        return 0

    def next(self):
        super().next()
        # dt =  self.datas[0].datetime.datetime(0)

        if self.order:
            return
    
        if not self.position:
            # === 做多信号 ===
            if self.crossover[0] > 0:  # 价格上穿EMA
                self.signal_bar = len(self)  # 记录信号K线位置
                return

            # 检查信号后的确认K线（做多）
            if hasattr(self, 'signal_bar') and self.signal_bar is not None:
                # 情况1：信号后第1根K线是阳线 → 直接开仓
                if len(self) == self.signal_bar + 1 and self.data.close[-1] > self.data.open[-1]:
                    self.log("满足情况1开多")
                    self._execute_long_order()
    
                # 情况2：信号后第1根K线不是阳线 → 检查第2根K线
                elif len(self) == self.signal_bar + 2:
                    # 第2根K线必须是阳线，且收盘价在EMA上方
                    if (self.data.close[-1] > self.data.open[-1]) and (self.data.close[-1] > self.ema[0]):
                        self.log("满足情况2开多")
                        self._execute_long_order()
                    # 无论是否开仓，信号处理完成后重置
                    delattr(self, 'signal_bar')
    
            # === 做空信号 ===
            elif self.crossover[0] < 0:  # 价格下穿EMA
                self.signal_bar = len(self)
                return
    
            # 检查信号后的确认K线（做空）
            if hasattr(self, 'signal_bar')  and self.signal_bar is not None:
                # 情况1：信号后第1根K线是阴线 → 直接开仓
                if len(self) == self.signal_bar + 1 and self.data.close[-1] < self.data.open[-1]:
                    self._execute_short_order()
    
                # 情况2：信号后第1根K线不是阴线 → 检查第2根K线
                elif len(self) == self.signal_bar + 2:
                    # 第2根K线必须是阴线，且收盘价在EMA下方
                    if (self.data.close[-1] < self.data.open[-1]) and (self.data.close[-1] < self.ema[0]):
                        self._execute_short_order()
                    # 无论是否开仓，信号处理完成后重置
                    delattr(self, 'signal_bar')
    
        # === 平仓逻辑 ===
        elif self.position:
            # 1. 达到目标价 → 部分平仓
            if self.position.size > 0 and self.data.close[0] >= self.target_price:  # 做多
                self.close(size=self.position.size // 2)
                # self.stop_price = self.my_entry_price * 1.01  # 保本止损（可选）
            elif self.position.size < 0 and self.data.close[0] <= self.target_price:  # 做空
                self.close(size=abs(self.position.size) // 2)
                # self.stop_price = self.my_entry_price * 0.99  # 保本止损（可选）
    
            # 2. 触发止损 → 全部平仓
            if (self.position.size > 0 and self.data.close[0] <= self.stop_price) or \
            (self.position.size < 0 and self.data.close[0] >= self.stop_price):
                self.close()
    
            # 3. 收盘价跌破EMA → 全部平仓（趋势反转）
            if (self.position.size > 0 and self.data.close[0] < self.ema[0]) or \
            (self.position.size < 0 and self.data.close[0] > self.ema[0]):
                self.close()



    # === 封装开仓方法（避免重复代码） ===
    def _execute_long_order(self):
        self.stop_price = self.data.low[-1]  # 止损设为入场K线最低点
        self.size = self.calculate_position_size()
        if self.size > 0:
            self.buy(size=self.size)
            self.my_entry_price = self.data.close[0]
            stop_loss_pct = abs(self.my_entry_price - self.stop_price) / self.my_entry_price
            self.target_price = self.my_entry_price * (1 + 2 * stop_loss_pct)
    
    def _execute_short_order(self):
        self.stop_price = self.data.high[-1]  # 止损设为入场K线最高点
        self.size = self.calculate_position_size()
        if self.size > 0:
            self.sell(size=self.size)
            self.my_entry_price = self.data.close[0]
            stop_loss_pct = abs(self.my_entry_price - self.stop_price) / self.my_entry_price
            self.target_price = self.my_entry_price * (1 - 2 * stop_loss_pct)